﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using OME.Storage;

using System.Messaging;

namespace OME
{
   public class QuoteServer
   {
      Generator gen = new Generator();
      BizDomain bd;
      Order order;
      Socket mdpSocket;
      Socket mdcSocket;
      Socket tcpSocket;
      IPAddress groupAddress;
      IPEndPoint mcastEP;
      IPEndPoint localEP;
      byte[] receiveBuffer = new byte[4096];
      string mktPrice;
      int quoteNum;
      public bool knewQuotes;
      bool existingQuotes;
      bool man;
      ManualResetEvent processSignaller;   
      public List<Order> qList = new List<Order>();
      List<string> input = new List<string>();
      string ser;
      bool runOnce;
      bool runOnce2 = false;

      public QuoteServer(int num, BizDomain domain)
      {
         bd = domain;
         quoteNum = num;
         //IP Multicast address
         groupAddress = IPAddress.Parse("224.5.6.7");
         mcastEP = new IPEndPoint(groupAddress, 30002);
         
         existingQuotes = false;
         man = false;
         processSignaller = new ManualResetEvent(false);
         ser = null;
         order = null;       
         knewQuotes = false;
         runOnce = false;

         
      }

      public void StartListener()
      {
         if (runOnce == false)
         {
            knewQuotes = true;
            for (int i = 0; i < bd.oprocNames.Length; i++)
            {
               input.Add(bd.oprocNames[i]);
               GenerateOrder(bd.oprocNames[i]);
            }
            knewQuotes = false;
            runOnce = true;
         }
         string test = ser;
         localEP = new IPEndPoint(IPAddress.Loopback, 20000);
         Console.WriteLine("Market-Data Producer Service Started - (Using MultiCast)");
         Console.WriteLine("Waiting for service input ... ");
         
         tcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
         tcpSocket.Bind(localEP);
         tcpSocket.Listen(10);
         mdcSocket = tcpSocket.Accept();
         tcpSocket.Close();
         EndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
         int bytesReceived = mdcSocket.ReceiveFrom(receiveBuffer, ref endPoint);
         IPEndPoint mdpEndPoint = (IPEndPoint)endPoint;
         ser = Encoding.ASCII.GetString(receiveBuffer, 0, bytesReceived);
         if (ser != null && !ser.Equals(test) && ser.Length == 4)
         {
            if (!input.Contains(ser))
            {
               input.Add(ser);
               knewQuotes = true;
               GenerateOrder(ser);
            }
            else
               existingQuotes = true;
         }
         else if (ser.Length == 5)
            bd.logic.RegisterTrader(ser);
         else
         {
            knewQuotes = true;
            man = true;
            GenerateOrder(ser);
         }
            
         if (bytesReceived > 0 )
         {
            mdcSocket.Close();
            Console.WriteLine("new thread for listening started");
            StartListener();
         }        
      }

      public void GenerateOrder(string service)
      {         
         for (int i = 0; i < quoteNum; i++)
         {
            if (knewQuotes)
            {
               order = gen.generateOrder(service);
               bd.orderList.Add(order);
               if (man)
               {
                  man = false;
                  break;
               }
            }
         }

         if (bd.orderList != null && bd.orderList.Count > 0)
         {
            if (!bd.orderList.Contains(order))
               bd.orderList.Add(order);
            foreach (Order o in bd.orderList)
               bd.SubmitOrder(o.Instrument, o);
         }
      }

      public void ReturnQuotes()
      {
         lock (qList)
         {
            byte[] sendBuffer = new byte[4096];

            if (knewQuotes == true)
            {
               mdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

               for (int i = 0; i < bd.orderList.Count; i++)
               {
                  order = bd.orderList.ElementAt(i);
                  if (order.Instrument.Equals(ser)
                     && !qList.Contains(order))
                     qList.Add(order);

               }

               qList.Sort(delegate(Order thisItem, Order otherItem)
               {
                  return thisItem.Price.CompareTo(otherItem.Price);
               });

               for (int i = 0; i < qList.Count; i++)
               {
                  order = qList.ElementAt(i);
                  mktPrice = order.ToString();

                  mktPrice = mktPrice + "ORDR";

                  if (order.Equals(qList.Last()))
                  {
                      mktPrice += "~";
                  }

                  Console.WriteLine("sending order " + mktPrice);
                  sendBuffer = Encoding.ASCII.GetBytes(mktPrice);
                  //Set multicast TTL
                  mdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 3);
                  //Send data to multicast address
                  mdpSocket.SendTo(sendBuffer, mcastEP);
               }
               qList.Clear();
               knewQuotes = false;
               //mdpSocket.Close();

               //mdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

               //            Console.WriteLine("sending XML");
               sendBuffer = Encoding.ASCII.GetBytes(GetMsg());
               Console.WriteLine("byte size: " + sendBuffer.Length.ToString());
               //Set multicast TTL
               mdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 3);
               //Send data to multicast address
               mdpSocket.SendTo(sendBuffer, mcastEP);

            }
            else if (existingQuotes)
            {

               mdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

               for (int i = 0; i < bd.orderList.Count; i++)
               {
                  order = bd.orderList.ElementAt(i);
                  if (order.Instrument.Equals(ser)
                     && !qList.Contains(order))
                     qList.Add(order);

               }

               qList.Sort(delegate(Order thisItem, Order otherItem)
               {
                  return thisItem.Price.CompareTo(otherItem.Price);
               });

               for (int i = 0; i < qList.Count; i++)
               {
                  order = qList.ElementAt(i);
                  mktPrice = order.ToString();

                  mktPrice = mktPrice + "ORDR";

                  if (order.Equals(qList.Last()))
                  {
                      mktPrice += "~";
                  }

                  Console.WriteLine("sending order " + mktPrice);
                  sendBuffer = Encoding.ASCII.GetBytes(mktPrice);
                  //Set multicast TTL
                  mdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 3);
                  //Send data to multicast address
                  mdpSocket.SendTo(sendBuffer, mcastEP);

               }
               qList.Clear();
               existingQuotes = false;

                if (!runOnce2)
                {
                    //mdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

                    //            Console.WriteLine("sending XML");
                    sendBuffer = Encoding.ASCII.GetBytes(GetMsg());
                    Console.WriteLine("byte size: " + sendBuffer.Length.ToString());
                    //Set multicast TTL
                    mdpSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 3);
                    //Send data to multicast address
                    mdpSocket.SendTo(sendBuffer, mcastEP);

                    runOnce = true;
                }

            }
          }
      }
      private static string GetMsg()
      {
          MessageQueue tQueue = new MessageQueue(@".\Private$\TradeQueue");
          tQueue.Formatter = new XmlMessageFormatter(new string[] { "System.String" });

          MessageEnumerator qEnum = tQueue.GetMessageEnumerator2();

          //_XML here for delimiter in Broadcast string
          String xmlMsg = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><TQ>";

          while (qEnum.MoveNext())
          {
              xmlMsg += qEnum.Current.Body.ToString();
          }

          xmlMsg += "</TQ>~";

          string retval = xmlMsg.ToString();

          return retval;
      }
   }
}
